package com.littlerpc.proxy.proxy;

import com.littlerpc.protocol.codec.Serializer;
import com.littlerpc.protocol.net.common.*;
import com.littlerpc.registry.zookeeper.ZookeeperDiscovery;

import java.lang.reflect.Constructor;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;

/**
 *
 * @author ChengPeng
 * @date 2017/7/6
 * 用于缓存客户端，这样，就不用每次都需要创建了
 */
public class RpcClientPoolUtil {

    private static final Map<String, RpcClient> CLIENT_POOL = new ConcurrentHashMap<>(16);
    /**
     * 获取序列化
     */
    public static Serializer serializer(String serializer) {
        return SerializerEnum.match(serializer);
    }

    /**
     * 获取RpcClient
     */
    public static RpcClient rpcClient(RemoteClientInfo info) throws Exception {
        String host = null;
        int port = 0;
        if (info.isZk() && info.getZkConf() != null) {
            ZookeeperDiscovery zd = new ZookeeperDiscovery(info.getZkConf());
            Set<String> providerListCache = zd.getProviderListCache();
            //获取ip 进行解析
            int index = 0;
            int randomIndex = getRandomInt(providerListCache.size());
            Iterator<String> iterator = providerListCache.iterator();
            while (iterator.hasNext()) {
                if (index == randomIndex) {
                    String[] hostInfo = iterator.next().split(":");
                    host = hostInfo[0];
                    port = Integer.parseInt(hostInfo[1]);
                    break;
                }
            }
        } else {
            host = info.getRemoteHost();
            port = info.getRemotePort();
        }

        String clientKey = host+"_"+port;

        if(CLIENT_POOL.containsKey(clientKey)) {
            return CLIENT_POOL.get(clientKey);
        }

        Class<? extends RpcClient> clientClass = NetProtocolClientEmum.match(info.getProtocol());
        Constructor<? extends RpcClient> constructor = clientClass.getConstructor(RpcClient.constructorParameterTypes);
        RpcClient rpcClient = constructor.newInstance(host, port, serializer(info.getSerializer()));
        CLIENT_POOL.putIfAbsent(clientKey,rpcClient);
        return rpcClient;

    }

    /**
     * 获得一个[0,max)之间的随机整数。
     */
    public static int getRandomInt(int max) {
        return getRandom().nextInt(max);
    }

    /**
     * 双重校验锁获取一个Random单例
     */
    public static ThreadLocalRandom getRandom() {
        return ThreadLocalRandom.current();
    }
}
